#include "Army.hpp"
#include "defines.hpp"
#include "BattlePredictor.hpp"
#include <cmath>

using namespace BWAPI;
using namespace std;

Army::Army()
:	m_state(none),
	m_updateInterval(10),
	m_updateCounter(0)
{
	if (Broodwar->self()->getRace() == Races::Terran) {
		m_mode = ArmyMode::defend;
	}
	if (Broodwar->self()->getRace() == Races::Zerg) {
		m_mode = ArmyMode::attack;
	}
}

void Army::tacticReavaluation()
{
	if (m_rangedSquad.size()+m_meleeSquad.size() == 0 
		|| m_enemySquad.size() == 0) {
		m_LOC.set(m_initialPosition, 0, 0);
		return;
	}
	/*BattlePredictor battlePredictor;
	m_enemySquad.addToBattlePredictor( battlePredictor );
	m_rangedSquad.addToBattlePredictor( battlePredictor );
	battlePredictor.runSimulation();*/

	if (m_mode == ArmyMode::defend) {
		if (m_state == ArmyState::none) {
			if (inRange()) {
				m_state = ArmyState::fight;
				return;
			}
			Position enemyPosition = m_enemySquad.getPosition();
			double enemyDir = atan2(double(enemyPosition.y()-m_initialPosition.y()), double(enemyPosition.x()-m_initialPosition.x()));
			m_LOC.set(m_initialPosition, enemyDir, 32*10);
			m_rangedSquad.formLine( m_LOC.createParallelLine(-64) );
			m_meleeSquad.formLine( m_LOC.createParallelLine(-32) );
		} else if (m_state == ArmyState::fight) {
		}
	} else if (m_mode == ArmyMode::attack) {
		if (m_state == ArmyState::none) {
			m_state = ArmyState::stageForAttack;
		}
		if (m_state == ArmyState::stageForAttack) {
			if (inRange()) {
				m_state = ArmyState::fight;
				return;
			}
			Position enemyPosition = m_enemySquad.getPosition();
			double enemyDir = atan2(double(enemyPosition.y()-m_initialPosition.y()), double(enemyPosition.x()-m_initialPosition.x()));
			Line enemyLine(enemyPosition, enemyDir, 32*10);
			int avgD2 = m_meleeSquad.formLine( enemyLine.createParallelLine(-200) );
			Line meleeLine(m_meleeSquad.getPosition(), enemyDir, 32*10);
			avgD2 += m_rangedSquad.formLine( meleeLine.createParallelLine(-32) );
			if (avgD2<2*16*16) {
				m_state = ArmyState::fight;
				return;
			}
		} else if (m_state == ArmyState::fight) {
		}
	}
}

void Army::addUnit(
	BWAPI::Unit *u
)
{
	if (u->getPlayer() == Broodwar->self()) {
		if (u->getType() == UnitTypes::Protoss_Dragoon) {
			m_rangedSquad.addUnit(u);
		}
		if (u->getType() == UnitTypes::Protoss_Zealot) {
			m_meleeSquad.addUnit(u);
		}
	}
	if (u->getPlayer() == Broodwar->enemy()) {
		m_enemySquad.addUnit(u);
	}
	m_initialPosition = m_rangedSquad.getPosition();
}

void Army::removeUnit(
	BWAPI::Unit *u
)
{
	m_rangedSquad.removeUnit(u);
	m_meleeSquad.removeUnit(u);
	m_enemySquad.removeUnit(u);
}

void Army::onFrame()
{
	m_rangedSquad.onFrame();
	m_meleeSquad.onFrame();
	if (m_updateCounter-- == 0) {
		m_updateCounter = m_updateInterval;
		tacticReavaluation();
	}
	if (m_state == ArmyState::fight) {
		m_rangedSquad.onFrameAttack( m_enemySquad.getPosition() );
		m_meleeSquad.onFrameAttack( m_enemySquad.getPosition() );
	}
	draw();
#ifdef DISPLAY_ENEMY_ATTACK_RANGE
	displayEnemyRange();
#endif
}

bool Army::inRange()
{
	vector<Unit*> enemyUnits;
	m_enemySquad.addToVector( enemyUnits );
	vector<Unit*> myUnits;
	m_rangedSquad.addToVector( myUnits );
	m_meleeSquad.addToVector( myUnits );
	for (int i=0 ; i<enemyUnits.size() ; i++) {
		int range2 = enemyUnits[i]->getType().groundWeapon().maxRange() + 32;
		range2 = range2*range2;
		Position p = enemyUnits[i]->getPosition();
		for (int j=0 ; j<myUnits.size() ; j++) {
			Position p2 = myUnits[j]->getPosition();
			if (CALC_D2(p,p2) < range2) {
				return true;
			}
		}
	}
	return false;
}

void Army::draw() const
{
	Broodwar->drawCircleMap(m_initialPosition.x(), m_initialPosition.y(), 10, Colors::Blue);
	Broodwar->drawTextScreen(5,0,"Army: m_initialPosition %d, %d", m_initialPosition.x(), m_initialPosition.y());
	Broodwar->drawTextScreen(5,12,"Army: m_rangedSquad %d, m_meleeSquad %d, m_enemySquad %d", m_rangedSquad.size(), m_meleeSquad.size(), m_enemySquad.size());
	if (m_mode==ArmyMode::attack) {
		Broodwar->drawTextScreen(5,24,"Army: ArmyMode = attack");
	} else if (m_mode==ArmyMode::defend) {
		Broodwar->drawTextScreen(5,24,"Army: ArmyMode = defend");
	}
	if (m_state==ArmyState::fight) {
		Broodwar->drawTextScreen(5,36,"Army: ArmyState = fight");
	} else if (m_state==ArmyState::stageForAttack) {
		Broodwar->drawTextScreen(5,36,"Army: ArmyState = stageForAttack");
	} else if (m_state==ArmyState::none) {
		Broodwar->drawTextScreen(5,36,"Army: ArmyState = none");
	}
	m_LOC.draw( Colors::Purple );
	Position enemyPosition = m_enemySquad.getPosition();
}

void Army::displayEnemyRange() const
{
/*	for (set<Unit*>::const_iterator i=m_enemySquad.m_units.begin() ; i!=m_enemyUnits.m_units.end() ; i++) {
		Position p = (*i)->getPosition();
		int r = (*i)->getType().groundWeapon().maxRange();
		Broodwar->drawCircleMap(p.x(), p.y(), r, BWAPI::Colors::Red);
	} */
}
